En omfattende guide til Cross-Origin Resource Sharing (CORS), som dekker konfigurasjon, sikkerhetsimplikasjoner og beste praksis for utviklere.
Cross-Origin Resource Sharing (CORS): Konfigurasjon og beste praksis for sikkerhet
I webutviklingens verden er sikkerhet avgjørende. Et kritisk aspekt ved websikkerhet er å administrere hvordan nettsider fra én opprinnelse kan få tilgang til ressurser fra en annen. Det er her Cross-Origin Resource Sharing (CORS) kommer inn i bildet. CORS er en sikkerhetsfunksjon i nettleseren som begrenser nettsider fra å gjøre forespørsler til et annet domene enn det som serverte nettsiden. Denne mekanismen er på plass for å forhindre at ondsinnede nettsteder får tilgang til sensitive data. Denne artikkelen gir en omfattende guide til CORS, og dekker konfigurasjon, sikkerhetsimplikasjoner og beste praksis.
Forståelse av Same-Origin Policy
CORS bygger på fundamentet til Same-Origin Policy, en grunnleggende sikkerhetsmekanisme implementert av nettlesere. Same-origin policy begrenser nettsider fra å gjøre forespørsler til et annet domene enn det som serverte nettsiden. To URL-er anses å ha samme opprinnelse hvis de har samme protokoll (f.eks. HTTP eller HTTPS), vert (f.eks. example.com) og port (f.eks. 80 eller 443). For eksempel:
http://example.comoghttp://example.com/pathhar samme opprinnelse.http://example.comoghttps://example.comhar ulik opprinnelse (forskjellige protokoller).http://example.comoghttp://www.example.comhar ulik opprinnelse (forskjellige verter).http://example.com:80oghttp://example.com:8080har ulik opprinnelse (forskjellige porter).
Same-origin policy er designet for å forhindre Cross-Site Scripting (XSS)-angrep, der et ondsinnede nettsted injiserer skript inn i et pålitelig nettsted for å stjele brukerdata eller utføre uautoriserte handlinger. Uten same-origin policy kunne et ondsinnede nettsted potensielt få tilgang til bankkontoinformasjonen din hvis du var logget inn på nettbanken din i en annen fane.
Hva er Cross-Origin Resource Sharing (CORS)?
Selv om same-origin policy er avgjørende for sikkerheten, kan den også være restriktiv i legitime scenarier der nettsteder trenger tilgang til ressurser fra forskjellige opprinnelser. For eksempel kan en webapplikasjon som hostes på example.com trenge å hente data fra et API som hostes på api.example.net. CORS gir en mekanisme for å omgå same-origin policy på en kontrollert måte, slik at nettsider kan gjøre forespørsler på tvers av opprinnelser når det er eksplisitt autorisert av serveren.
CORS fungerer ved å legge til HTTP-headere i responsen fra serveren, som indikerer hvilke opprinnelser som har lov til å få tilgang til ressursen. Nettleseren sjekker deretter disse headerne og blokkerer forespørselen hvis opprinnelsen til nettsiden som gjør forespørselen ikke er tillatt.
Hvordan CORS fungerer: HTTP-headerne
CORS er avhengig av spesifikke HTTP-headere for å fasilitere forespørsler på tvers av opprinnelser. Her er de sentrale headerne som er involvert:
1. Origin (Forespørselsheader)
Origin-headeren sendes av nettleseren i forespørsler på tvers av opprinnelser. Den indikerer opprinnelsen (protokoll, vert og port) til nettsiden som gjør forespørselen. For eksempel:
Origin: http://example.com
2. Access-Control-Allow-Origin (Responsheader)
Access-Control-Allow-Origin-headeren er den viktigste headeren i CORS. Den spesifiserer hvilke opprinnelser som har lov til å få tilgang til ressursen. Den kan ha en av følgende verdier:
- En spesifikk opprinnelse: For eksempel tillater
Access-Control-Allow-Origin: http://example.comkun forespørsler frahttp://example.com. *(wildcard):Access-Control-Allow-Origin: *tillater forespørsler fra enhver opprinnelse. Dette bør brukes med forsiktighet, da det effektivt deaktiverer same-origin policy for den ressursen.
Eksempel:
Access-Control-Allow-Origin: https://www.example.com
3. Access-Control-Allow-Methods (Responsheader)
Access-Control-Allow-Methods-headeren spesifiserer HTTP-metodene (f.eks. GET, POST, PUT, DELETE) som er tillatt i forespørselen på tvers av opprinnelser. Dette er påkrevd for preflight-forespørsler (forklart nedenfor).
Eksempel:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
4. Access-Control-Allow-Headers (Responsheader)
Access-Control-Allow-Headers-headeren spesifiserer HTTP-headerne som er tillatt i forespørselen på tvers av opprinnelser. Dette er også påkrevd for preflight-forespørsler.
Eksempel:
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
5. Access-Control-Allow-Credentials (Responsheader)
Access-Control-Allow-Credentials-headeren spesifiserer om nettleseren skal inkludere legitimasjon (f.eks. cookies, autorisasjonsheadere) i forespørselen på tvers av opprinnelser. Den kan ha en av to verdier: true eller false. Hvis true er satt, kan Access-Control-Allow-Origin-headeren ikke settes til *. Den må være en spesifikk opprinnelse.
Eksempel:
Access-Control-Allow-Credentials: true
6. Access-Control-Max-Age (Responsheader)
Access-Control-Max-Age-headeren spesifiserer antall sekunder nettleseren kan bufre resultatene av preflight-forespørselen. Dette kan forbedre ytelsen ved å redusere antall preflight-forespørsler.
Eksempel:
Access-Control-Max-Age: 3600
Enkle forespørsler vs. preflight-forespørsler
CORS skiller mellom to typer forespørsler på tvers av opprinnelser: enkle forespørsler og preflight-forespørsler.
Enkle forespørsler
En enkel forespørsel er en forespørsel som oppfyller følgende kriterier:
- Metoden er
GET,HEAD, ellerPOST. - Hvis metoden er
POST, erContent-Type-headeren en av følgende:application/x-www-form-urlencoded,multipart/form-data, ellertext/plain. - Forespørselen setter ingen egendefinerte headere (annet enn de som automatisk settes av nettleseren).
For enkle forespørsler sender nettleseren forespørselen direkte til serveren. Serveren svarer deretter med de passende CORS-headerne. Hvis opprinnelsen er tillatt, behandler nettleseren responsen. Ellers blokkerer nettleseren responsen og kaster en feil.
Preflight-forespørsler
En preflight-forespørsel sendes av nettleseren før den faktiske forespørselen på tvers av opprinnelser gjøres, hvis forespørselen ikke oppfyller kriteriene for en enkel forespørsel. Dette skjer vanligvis når forespørselen bruker en annen metode enn GET, HEAD eller POST, eller når forespørselen setter egendefinerte headere.
Preflight-forespørselen er en OPTIONS-forespørsel som inkluderer følgende headere:
Origin: Opprinnelsen til nettsiden som gjør forespørselen.Access-Control-Request-Method: HTTP-metoden som vil bli brukt i den faktiske forespørselen.Access-Control-Request-Headers: En kommadelt liste over de egendefinerte headerne som vil bli brukt i den faktiske forespørselen.
Serveren svarer deretter med følgende headere:
Access-Control-Allow-Origin: Opprinnelsen som har lov til å få tilgang til ressursen.Access-Control-Allow-Methods: HTTP-metodene som er tillatt i forespørselen på tvers av opprinnelser.Access-Control-Allow-Headers: HTTP-headerne som er tillatt i forespørselen på tvers av opprinnelser.Access-Control-Max-Age: Antall sekunder nettleseren kan bufre resultatene av preflight-forespørselen.
Hvis serveren svarer med de passende CORS-headerne, fortsetter nettleseren med den faktiske forespørselen på tvers av opprinnelser. Ellers blokkerer nettleseren forespørselen og kaster en feil.
Eksempler på CORS-konfigurasjon
Implementeringen av CORS varierer avhengig av server-side-teknologien du bruker. Her er noen eksempler for vanlige server-side-språk og rammeverk:
Node.js med Express
Å bruke cors-middleware er en vanlig tilnærming for å konfigurere CORS i Node.js med Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Aktiver CORS for alle opprinnelser
app.use(cors());
// Aktiver CORS for en spesifikk opprinnelse
// app.use(cors({ origin: 'http://example.com' }));
// Aktiver CORS med alternativer
// app.use(cors({
// origin: ['http://example.com', 'http://localhost:3000'],
// methods: ['GET', 'POST', 'PUT', 'DELETE'],
// allowedHeaders: ['Content-Type', 'Authorization'],
// credentials: true
// }));
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from the API!' });
});
app.listen(3001, () => {
console.log('Server listening on port 3001');
});
Python med Flask
Du kan bruke Flask-CORS-utvidelsen for å konfigurere CORS i Flask:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
// Aktiver CORS for alle opprinnelser
CORS(app)
// Aktiver CORS for spesifikke opprinnelser
// CORS(app, origins=['http://example.com', 'http://localhost:3000'])
@app.route('/api/data')
def get_data():
return {'message': 'Hello from the API!'}
if __name__ == '__main__':
app.run(port=3001)
Java med Spring Boot
Spring Boot gir flere måter å konfigurere CORS på. En tilnærming er å bruke @CrossOrigin-annotasjonen:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Spesifikk opprinnelse
public class ApiController {
@GetMapping("/api/data")
public String getData() {
return "Hello from the API!";
}
}
// Global CORS-konfigurasjon (ved hjelp av WebMvcConfigurer):
// @Configuration
// public class CorsConfig implements WebMvcConfigurer {
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedOrigins("http://example.com", "http://localhost:3000")
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// .allowedHeaders("Content-Type", "Authorization")
// .allowCredentials(true)
// .maxAge(3600);
// }
// }
PHP
I PHP kan du sette CORS-headerne direkte i skriptet ditt:
<?php
header("Access-Control-Allow-Origin: http://example.com");
header("Content-Type: application/json");
$data = array("message" => "Hello from the API!");
echo json_encode($data);
?>
Sikkerhetshensyn ved CORS
Selv om CORS muliggjør forespørsler på tvers av opprinnelser, er det avgjørende å forstå sikkerhetsimplikasjonene og implementere det korrekt for å unngå sårbarheter.
1. Unngå å bruke Access-Control-Allow-Origin: * i produksjon
Å bruke wildcardet * i Access-Control-Allow-Origin-headeren tillater forespørsler fra enhver opprinnelse, noe som effektivt deaktiverer same-origin policy for den ressursen. Dette kan eksponere API-et ditt for ondsinnede nettsteder som potensielt kan stjele brukerdata eller utføre uautoriserte handlinger. Spesifiser i stedet de nøyaktige opprinnelsene som har lov til å få tilgang til ressursen. For eksempel, hvis webapplikasjonen din er hostet på example.com og trenger tilgang til et API hostet på api.example.com, sett headeren til Access-Control-Allow-Origin: http://example.com.
Globalt eksempel: Se for deg et API for en finansiell tjeneste som setter Access-Control-Allow-Origin: *. Et ondsinnede nettsted kan da gjøre forespørsler til dette API-et på vegne av en innlogget bruker, og potensielt overføre midler uten brukerens viten.
2. Valider Origin-headeren på serveren
Selv om du spesifiserer en liste over tillatte opprinnelser, er det viktig å validere Origin-headeren på serveren for å forhindre at angripere forfalsker opprinnelsen. En angriper kan potensielt sende en forespørsel med en forfalsket Origin-header for å omgå CORS-sjekkene. For å redusere dette, sammenlign Origin-headeren med en liste over klarerte opprinnelser på server-siden. Hvis opprinnelsen ikke er i listen, avvis forespørselen.
Globalt eksempel: Vurder en e-handelsplattform. En angriper kan forsøke å etterligne en legitim butikkfronts Origin for å få tilgang til sensitiv kundedata fra e-handelsplattformens API.
3. Vær forsiktig med Access-Control-Allow-Credentials: true
Hvis du setter Access-Control-Allow-Credentials: true, kan Access-Control-Allow-Origin-headeren ikke settes til *. Den må være en spesifikk opprinnelse. Dette er fordi å tillate legitimasjon fra enhver opprinnelse kan skape en sikkerhetsrisiko, da det kan tillate ondsinnede nettsteder å få tilgang til brukerdata hvis de kan lure en bruker til å besøke deres side mens brukeren også er logget inn på målnettstedet. Denne innstillingen er viktig når man håndterer cookies eller autorisasjonsheadere.
Globalt eksempel: En sosial medieplattform som tillater forespørsler på tvers av opprinnelser med legitimasjon, krever nøye administrasjon for å forhindre uautorisert tilgang til brukerkontoer.
4. Konfigurer Access-Control-Allow-Methods og Access-Control-Allow-Headers korrekt
Tillat kun de HTTP-metodene og -headerne som er nødvendige for forespørslene på tvers av opprinnelser. Hvis du bare trenger å tillate GET- og POST-forespørsler, ikke tillat PUT, DELETE eller andre metoder. På samme måte, tillat bare de spesifikke headerne som applikasjonen din trenger. Altfor permissive konfigurasjoner kan øke risikoen for angrep.
Globalt eksempel: Et CRM-system bør kun eksponere de nødvendige API-endepunktene og -headerne til autoriserte tredjepartsintegrasjoner, for å minimere angrepsflaten.
5. Bruk HTTPS for sikker kommunikasjon
Bruk alltid HTTPS for sikker kommunikasjon mellom nettleseren og serveren. HTTPS krypterer dataene som overføres mellom nettleseren og serveren, og forhindrer avlytting og man-in-the-middle-angrep. Bruk av HTTP kan eksponere sensitive data for angripere, selv om CORS er konfigurert korrekt.
Globalt eksempel: Helseapplikasjoner må bruke HTTPS for å beskytte pasientdata som overføres på tvers av forskjellige opprinnelser.
6. Content Security Policy (CSP)
Selv om det ikke er direkte relatert til CORS, er Content Security Policy (CSP) en annen viktig sikkerhetsmekanisme som kan bidra til å forhindre XSS-angrep. CSP lar deg definere en hviteliste over kilder som nettleseren har lov til å laste ressurser fra. Dette kan bidra til å forhindre at angripere injiserer ondsinnede skript på nettstedet ditt, selv om de klarer å omgå andre sikkerhetstiltak.
Globalt eksempel: Finansinstitusjoner bruker ofte strenge CSP-policyer for å begrense kildene til innhold som lastes inn på deres nettbankportaler, noe som reduserer risikoen for XSS-angrep.
Vanlige CORS-problemer og feilsøking
CORS-feil kan være frustrerende å feilsøke. Her er noen vanlige problemer og hvordan du kan feilsøke dem:
1. "No 'Access-Control-Allow-Origin' header is present on the requested resource."
Dette er den vanligste CORS-feilen. Den indikerer at serveren ikke returnerer Access-Control-Allow-Origin-headeren i sitt svar. Sørg for at serveren er konfigurert til å sende de korrekte CORS-headerne for opprinnelsen til nettsiden som gjør forespørselen. Dobbeltsjekk server-side-koden og konfigurasjonsfilene dine.
2. "Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
Denne feilen indikerer at preflight-forespørselen mislyktes. Dette kan skje hvis serveren ikke svarer på OPTIONS-forespørsler eller hvis serveren returnerer en feilstatuskode (f.eks. 404, 500) som svar på preflight-forespørselen. Sørg for at serveren din er konfigurert til å håndtere OPTIONS-forespørsler og at den returnerer en 200 OK-statuskode.
3. "Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'."
Denne feilen oppstår når du prøver å sende legitimasjon (f.eks. cookies) i en forespørsel på tvers av opprinnelser og Access-Control-Allow-Origin-headeren er satt til *. Som nevnt tidligere, kan du ikke bruke wildcardet * når du sender legitimasjon. Du må spesifisere den nøyaktige opprinnelsen som har lov til å få tilgang til ressursen.
4. Nettleser-caching
Nettlesere kan bufre CORS-responser, noe som kan føre til uventet oppførsel hvis CORS-konfigurasjonen endres. For å forhindre cache-problemer, sett Cache-Control-headeren i responsen til no-cache, no-store, eller max-age=0. Du kan også bruke Access-Control-Max-Age-headeren til å kontrollere hvor lenge nettleseren bufrer resultatene av preflight-forespørselen.
Alternativer til CORS
Selv om CORS er standardmåten for å muliggjøre forespørsler på tvers av opprinnelser, finnes det noen alternativer du kan vurdere i visse scenarier:
1. JSON with Padding (JSONP)
JSONP er en teknikk som bruker <script>-taggen for å omgå same-origin policy. JSONP fungerer ved å pakke JSON-dataene inn i et JavaScript-funksjonskall. Nettleseren utfører deretter JavaScript-funksjonen og sender JSON-dataene som et argument. JSONP er enklere å implementere enn CORS, men det har noen begrensninger. Det støtter bare GET-forespørsler, og det er mindre sikkert enn CORS.
2. Omvendt proxy (Reverse Proxy)
En omvendt proxy er en server som sitter foran API-serveren din og videresender forespørsler til den. Den omvendte proxyen kan konfigureres til å legge til de nødvendige CORS-headerne i responsen, og dermed effektivt skjule forespørslene på tvers av opprinnelser for nettleseren. Denne tilnærmingen kan være nyttig hvis du ikke har kontroll over API-serveren eller hvis du ønsker å forenkle CORS-konfigurasjonen.
Konklusjon
Cross-Origin Resource Sharing (CORS) er en avgjørende sikkerhetsmekanisme som lar nettsider få tilgang til ressurser fra forskjellige opprinnelser på en kontrollert måte. Å forstå hvordan CORS fungerer og implementere det korrekt er essensielt for å bygge sikre og pålitelige webapplikasjoner. Ved å følge beste praksis som er beskrevet i denne artikkelen, kan du effektivt administrere CORS og beskytte API-ene dine mot uautorisert tilgang.
Husk å alltid prioritere sikkerhet når du konfigurerer CORS. Unngå å bruke wildcards, valider Origin-headeren, og bruk HTTPS for sikker kommunikasjon. Ved å ta disse forholdsreglene kan du sikre at webapplikasjonene dine er beskyttet mot angrep på tvers av nettsteder.
Denne omfattende guiden gir et solid grunnlag for å forstå CORS. Se alltid den offisielle dokumentasjonen for din spesifikke server-side-teknologi for den mest oppdaterte informasjonen og beste praksis. Hold deg informert om nye sikkerhetstrusler og tilpass CORS-konfigurasjonen din deretter.